package logrus

import (
	"gitee.com/lipore/plume/logger"
	"os"

	"github.com/sirupsen/logrus"
)

func NewLogger(options *logger.Options) logger.Logger {
	var formatter logrus.Formatter
	if options.Format == logger.TextFormat {
		textFormatter := new(logrus.TextFormatter)
		textFormatter.FullTimestamp = true
		textFormatter.ForceColors = true
		formatter = textFormatter
	} else {
		jsonFormatter := new(logrus.JSONFormatter)
		formatter = jsonFormatter
	}
	hooks := make(logrus.LevelHooks)
	if options.OutputPaths != nil && len(options.OutputPaths) > 0 {
		hooks.Add(NewFileHook(options.OutputPaths, []logrus.Level{logrus.InfoLevel, logrus.WarnLevel}))
	}
	if options.ErrorOutputPaths != nil && len(options.ErrorOutputPaths) > 0 {
		hooks.Add(NewFileHook(options.ErrorOutputPaths, []logrus.Level{logrus.ErrorLevel, logrus.PanicLevel, logrus.FatalLevel}))
	}
	levels := []logrus.Level{logrus.DebugLevel, logrus.InfoLevel, logrus.WarnLevel, logrus.ErrorLevel, logrus.PanicLevel, logrus.FatalLevel}
	level := logger.INFO
	_ = level.Parse(options.Level)

	l := &logrus.Logger{
		Out:          os.Stdout,
		Formatter:    formatter,
		Hooks:        hooks,
		Level:        levels[level],
		ExitFunc:     os.Exit,
		ReportCaller: false,
	}
	return NewLogrusWrapper(l)
}

func NewLogrusWrapper(b logger.Base) logger.Logger {
	return &logrusWrapper{
		Base: b,
	}
}

func (l *logrusWrapper) V(level logger.Level) logger.StdLogger {
	switch log := l.Base.(type) {
	case *logrus.Logger:
		return &V{
			logWithLevel: log,
			level:        level,
		}
	case *logrus.Entry:
		return &V{
			logWithLevel: log,
			level:        level,
		}
	}
	return &V{
		logWithLevel: logrus.StandardLogger(),
		level:        level,
	}
}

type logrusWrapper struct {
	logger.Base
}

func (l *logrusWrapper) WithFields(fields map[string]interface{}) logger.Logger {
	switch log := l.Base.(type) {
	case *logrus.Logger:
		return NewLogrusWrapper(log.WithFields(fields))
	case *logrus.Entry:
		return NewLogrusWrapper(log.WithFields(fields))
	default:
		return l
	}
}

func mapLevel(level logger.Level) logrus.Level {
	switch level {
	case logger.DEBUG:
		return logrus.DebugLevel
	case logger.INFO:
		return logrus.InfoLevel
	case logger.WARN:
		return logrus.WarnLevel
	case logger.ERROR:
		return logrus.ErrorLevel
	case logger.PANIC:
		return logrus.PanicLevel
	case logger.FATAL:
		return logrus.FatalLevel
	}
	return logrus.InfoLevel
}

type logWithLevel interface {
	Log(level logrus.Level, i ...interface{})
	Logf(level logrus.Level, format string, args ...interface{})
	Logln(level logrus.Level, args ...interface{})
}

type V struct {
	logWithLevel
	level logger.Level
}

func (v *V) Print(i ...interface{}) {
	v.logWithLevel.Log(mapLevel(v.level), i...)
}

func (v *V) Printf(s string, i ...interface{}) {
	v.logWithLevel.Logf(mapLevel(v.level), s, i...)
}

func (v *V) Println(i ...interface{}) {
	v.logWithLevel.Logln(mapLevel(v.level), i...)
}

func init() {
	logger.SetupGlobalLogger(
		NewLogger(&logger.Options{
			ErrorOutputPaths: []string{},
			OutputPaths:      []string{},
			Level:            logger.INFO.String(),
			Name:             "test",
			EnableColor:      true,
			Format:           "text",
		}))
}
